package juc2.lock;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者-消费者模型：使用 ReentrantLock 和 Condition 实现
 * 生产者将产品放入队列，消费者从队列中取出产品
 * 队列满时，生产者等待；队列空时，消费者等待
 * await() 释放锁并进入等待状态，直到被唤醒或中断
 * signal() 唤醒一个在条件变量上等待的线程
 * signalAll() 唤醒在条件变量上等待的所有线程
 */
public class ProducerConsumerDemo {
    private final Lock lock = new ReentrantLock();
    // 条件变量1：队列满时，生产者等待
    private final Condition fullCondition = lock.newCondition();
    // 条件变量2：队列空时，消费者等待
    private final Condition emptyCondition = lock.newCondition();
    private final Queue<Integer> queue = new LinkedList<>();
    private final int MAX_SIZE = 5; // 队列最大容量

    // 生产者：向队列添加元素
    public void produce(int value) throws InterruptedException {
        lock.lock();
        try {
            // 队列满时，生产者等待
            while (queue.size() == MAX_SIZE) {
                System.out.println("队列满，生产者等待...");
                fullCondition.await(); // 释放锁，进入fullCondition等待队列
            }
            queue.add(value);
            System.out.println("生产：" + value + "，队列大小：" + queue.size());
            emptyCondition.signal(); // 唤醒一个等待的消费者
        } finally {
            lock.unlock();
        }
    }

    // 消费者：从队列取出元素
    public int consume() throws InterruptedException {
        lock.lock();
        try {
            // 队列空时，消费者等待
            while (queue.isEmpty()) {
                System.out.println("队列空，消费者等待...");
                emptyCondition.await(); // 释放锁，进入emptyCondition等待队列
            }
            int value = queue.poll();
            System.out.println("消费：" + value + "，队列大小：" + queue.size());
            fullCondition.signal(); // 唤醒一个等待的生产者
            return value;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ProducerConsumerDemo demo = new ProducerConsumerDemo();

        // 启动生产者线程
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    demo.produce(i);
                    Thread.sleep(100);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // 启动消费者线程
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    demo.consume();
                    Thread.sleep(200);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

